﻿using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class MeContext : MonoBehaviour
{

		void Update ()
		{
				contetFactory.step (this);
		}
	
		void FixedUpdate ()
		{
				contetFactory.stepOver ();
		}

		public static int getContextTick ()
		{
				return contetFactory.contextTick;
		}

		public static object CastCallBackLock = new object ();

		public static void addCastCallBack (CallBack callBack)
		{
				lock (CastCallBackLock) {
						contetFactory.castCallBackList.Add (callBack);
				}
		}

		public static void addCastEnumerator (InstanceData<IEnumerator> enumerator)
		{
				contetFactory.castEnumeratorList.Add (enumerator);
		}

		public static void addContextCallBack (InstanceData<bool, int> callBack)
		{
				addCastCallBack (() => {
						contetFactory.contextCallBackList.AddLast (callBack);});
		}

		public static void removeContextCallBack (InstanceData<bool, int> callBack)
		{
				addCastCallBack (() => {
						contetFactory.contextCallBackList.Remove (callBack);});
		}

		private static ContextFactory contetFactory = new ContextFactory ();

		private class ContextFactory
		{
				// context tick
				public int contextTick = Environment.TickCount;

				// contextCallBackList
				public LinkedList<InstanceData<bool, int>> contextCallBackList = new LinkedList<InstanceData<bool, int>> ();

				// Step Tick
				public int stepTick = Environment.TickCount;

				// Cast CallBack List
				public List<CallBack> castCallBackList = new List<CallBack> ();

				// Cast Enumerator List
				public List<InstanceData<IEnumerator>> castEnumeratorList = new List<InstanceData<IEnumerator>> ();

				// step tick
				public void step (MonoBehaviour mono)
				{
						if (stepTick >= 0) {
								contextTick = Environment.TickCount;
								List<CallBack> castCallBacks = castCallBackList;
								lock (CastCallBackLock) {
										castCallBackList = new List<CallBack> ();
								}

								foreach (CallBack callBack in castCallBacks) {
										callBack ();
								}

								foreach (InstanceData<IEnumerator> enumerator in castEnumeratorList) {
										mono.StartCoroutine (enumerator());
								}

								castEnumeratorList.Clear();
								//UnityEngine.Debug.Log("MeContextContextCallBackList:" + contextTick + ":" + stepTick);
								if ((contextTick - stepTick) >= 1000) {
										//UnityEngine.Debug.Log("MeContextContextCallBackList" + contextCallBackList.Count);
										stepTick = contextTick + 1000;
										LinkedListNode<InstanceData<bool, int>> contextCallBackNode = contextCallBackList.First;
										for (LinkedListNode<InstanceData<bool, int>> node = contextCallBackNode; node != null; node = contextCallBackNode) {
												contextCallBackNode = node.Next;
												if (node.Value (contextTick)) {
														contextCallBackList.Remove (node.Value);
												}
										}
								}

								stepTick = -stepTick;
						}
				}

				// step over
				public void stepOver ()
				{
						if (stepTick < 0) {
								stepTick = -stepTick;
						}
				}

		}
}
